home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / DIST / gc / GCOSDependent.c < prev    next >
C/C++ Source or Header  |  1991-10-15  |  18KB  |  623 lines

  1. /* begincopyright
  2.   Copyright (c) 1988,1990 Xerox Corporation. All rights reserved.
  3.   Use and copying of this software and preparation of derivative works based
  4.   upon this software are permitted. Any distribution of this software or
  5.   derivative works must comply with all applicable United States export
  6.   control laws. This software is made available AS IS, and Xerox Corporation
  7.   makes no warranty about the software, its performance or its conformity to
  8.   any specification. Any person obtaining a copy of this software is requested
  9.   to send their name and post office or electronic mail address to:
  10.     PCR Coordinator
  11.     Xerox PARC
  12.     3333 Coyote Hill Rd.
  13.     Palo Alto, CA 94304
  14.     
  15.   Parts of this software were derived from code bearing the copyright notice:
  16.   
  17.   Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  18.   This material may be freely distributed, provided this notice is retained.
  19.   This material is provided as is, with no warranty expressed or implied.
  20.   Use at your own risk.
  21.   
  22.   endcopyright */
  23. /*
  24.  * OSDependent.c
  25.  *
  26.  * Extremely primitive memory allocation stuff.
  27.  *
  28.  * Weiser, 1988.
  29.  *
  30.  * Demers, February 27, 1990 8:36:25 am PST
  31.  * Boehm, December 13, 1990 6:23:34 pm PST
  32.  */
  33.  
  34. #define START_PROC_HACK
  35. #define DEBUG_PAR_GC
  36. #undef DEBUG_PAR_GC
  37. #define DEBUG_SCHEDULING
  38. #undef DEBUG_SCHEDULING
  39. #include <sys/time.h>
  40. #include "xr/GCPrivate.h"
  41. #include "xr/Threads.h"
  42. #include "xr/ThreadsBackdoor.h"
  43. #include "xr/ThreadsSchedCtl.h"
  44. #include "xr/ThreadsMsg.h"
  45.  
  46. #define I_HOLD_ML(ml) (((XR_ML)(ml))->ml_holder == XR_currThread)
  47.  
  48.  
  49. /* 256MBytes max heap size */
  50. #define MAXHEAPSIZE (1024*1024*256)
  51.  
  52.  
  53. /* must be multiple of HBLKSIZE and a multiple of system pagesize */
  54. #define INITIAL_HEAP     8*HBLKSIZE
  55.  
  56.  
  57. /*
  58.  * Setup -- called before VPs are forked
  59.  */
  60.  
  61. static void
  62. XR_GCAddSharedSeg(seg)
  63.     XR_Seg seg;
  64. {
  65.     if( seg->seg_bytes > 0 ) {
  66.         XR_add_data_list( seg->seg_addr, seg->seg_addr + seg->seg_bytes );
  67.     }
  68. }
  69.  
  70. /* Mesa procs for parallel garbage collector */
  71. static XR_MesaProc KeepAwakeProc;
  72. static XR_MesaProc GC_daemon_proc;
  73.  
  74. void
  75. XR_SetupGC()
  76. {
  77.     word dummy;  /* something in my frame to take the address of */
  78.     struct hblk *thishbp;
  79.     
  80.  
  81.     /* WARNING: the following works only for machines    */
  82.     /* whose stacks grow toward smaller numbered addrs,    */
  83.     /* and only for operating systems that grow the    */
  84.     /* stack segment even if the stack pointer is not    */
  85.     /* "reasonable".  Undoubtedly there are many other    */
  86.     /* restrictions. */
  87.         GC_mark_stack_bottom = &dummy;
  88.         GC_mark_stack_bottom -= STACKGAP;
  89.         GC_mark_stack_top = GC_mark_stack_bottom;
  90.  
  91.     XR_InitializeMonitor(&GC_allocate_ml);
  92.     XR_InitializeMonitor(&GC_alloc_callback_ml);
  93.  
  94.     if (sizeof (struct hblk) != HBLKSIZE) {
  95.     GC_abort("HBLK size inconsistency");
  96.     }
  97.     if (sizeof (long) != sizeof (int)) {
  98.         GC_iprintf("Long and int are not the same.  GC will probably break.\n");
  99.     }
  100.     if (sizeof (long) != sizeof (bool)) {
  101.         GC_iprintf(
  102.         "Long and bool are not the same.  GC will probably break.\n");
  103.     }
  104.     
  105. #   ifdef ALIGN_DOUBLE
  106.     if (HDR_BYTES % 8 != 0) {
  107.         GC_abort("Improper header size");
  108.     }
  109. #   endif    
  110. #   ifdef MERGE_SIZES
  111.       GC_init_size_map();
  112. #   endif
  113.  
  114.     XR_GCAddSharedSeg( &(XR_sysArea->sa_sharedDataSeg) );
  115. #   ifdef UNDEFINED
  116.         XR_GCAddSharedSeg( &(XR_sysArea->sa_sharedCommonSeg) );
  117.         XR_GCAddSharedSeg( &(XR_sysArea->sa_sharedBSSSeg) );
  118. #   endif
  119.     GC_heapstart = ((char *)(XR_sysArea->sa_heapSeg.seg_addr));
  120.     if (GC_heapstart != (char *) HBLKPTR(GC_heapstart+HBLKSIZE-1)) {
  121.         GC_abort("Heapstart not properly aligned");
  122.     }
  123.     
  124.     if (XR_sysArea->sa_heapSeg.seg_bytes != 0) {
  125.         GC_abort("Nonempty heap segment at startup");
  126.     }
  127.     GC_heaplim = GC_heapstart;
  128.     
  129.     /* Set up initial heap.  */
  130.       if (!GC_expand_hp(divHBLKSZ(INITIAL_HEAP + HBLKSIZE-1), TRUE)) {
  131.         GC_abort("Cant create initial heap");
  132.       }
  133.     GC_register_displacement(0);  /* Pointers to the beginning of an */
  134.                         /* object are always OK.           */
  135.     GC_register_displacement(8);  /* PCedar, among others, uses 8 byte   */
  136.                         /* object headers.             */
  137.     GC_daemon_proc = XR_MakeMesaProc(GC_daemon,0);
  138.     GC_collector_setup();
  139.     {
  140.         static XR_Pointer GC_KeepAwake();
  141.         KeepAwakeProc = XR_MakeMesaProc(GC_KeepAwake, 0);
  142.     }
  143.     GC_RegisterCommands();
  144. }
  145.  
  146. /* ??? delete the following someday ... ??? */
  147. #ifndef XR_PRI_SYS_EXCLUSIVE
  148. # define XR_PRI_SYS_EXCLUSIVE XR_PRI_LAST
  149. #endif
  150.  
  151. /* Priorirty of "world stopped" collection */
  152. static XR_Pri gcExclusivePriority = XR_PRI_SYS_EXCLUSIVE;
  153.  
  154. /* Priorirty of background GC keep awake thread */
  155. static XR_Pri gcKeepAwakePriority = XR_PRI_SYS_FOREGROUND;
  156.  
  157. struct XR_CTRep GC_last_marker;  /* Last started parallel collection thread. */
  158.  
  159. # ifdef DEBUG_PAR_GC
  160.   struct XR_CTRep GC_last_forker; /* parent of GC_last_marker */
  161.   int GC_last_gc_no;
  162. # endif
  163.  
  164. # define WAKEUP_TICKS ((XR_Ticks)2)
  165.  
  166. # define MAXFRAMES 10
  167. typedef unsigned int stack_type[MAXFRAMES];
  168. # define NONE -1
  169.  
  170. # ifdef DEBUG_SCHEDULING
  171.  
  172. /* Trace back through the stack atrting at sp and save all pc values */
  173. /* in stack.                                 */
  174. void save_stack(sp,stack)
  175. register unsigned sp;
  176. register stack_type * stack;
  177. {
  178.     register int i = 0;
  179.     register unsigned nsp;
  180. #   define MAXDIF 64*1024
  181.  
  182.     if (sp < (unsigned)GC_heaplim
  183.         || sp > (unsigned)GC_heaplim + 0x10000000) goto finish;
  184.     while(i < MAXFRAMES) {
  185.         (*stack)[i++] = ((unsigned *)sp)[15];
  186.         nsp = ((unsigned *)sp)[14];
  187.         if(nsp < sp || nsp > sp + MAXDIF) break;
  188.         sp = nsp;
  189.     }
  190.   finish:
  191.     while(i < MAXFRAMES) {
  192.         (*stack)[i++] = NONE;
  193.     }
  194. }
  195.  
  196. void print_stack(s1)
  197. register stack_type *s1;
  198. {
  199.     register int i;
  200.     
  201.     for (i = 0; i < MAXFRAMES; i++) {
  202.         if ((*s1)[i] == NONE) break;
  203.         XR_ConsoleMsg("0x%X, ", (*s1)[i]);
  204.     }
  205.     XR_ConsoleMsg(" ...\n");
  206. }
  207.  
  208.  
  209. stack_type collector_stack;
  210.  
  211. # endif DEBUG_SCHEDULING
  212.  
  213. struct XR_CVRep GC_parallel_done_cv = { 0 };
  214.  
  215. bool GC_parallel_done_signalled = FALSE;
  216.  
  217. /* Signal completion of a parallel marker.  Not essential for correctness, */
  218. /* but avoids an unnecessary wait for a timeout.               */
  219. /* A superfluous call WILL break things.                   */
  220. void GC_parallel_done()
  221. {
  222.     GC_parallel_done_signalled = TRUE;
  223.     XR_Notify(&GC_parallel_done_cv);
  224. }
  225.  
  226. /* Repeatedly do a directed yield to thread t, with the fraction of       */
  227. /* time allocated to t increasing quadratically in the ratio         */
  228. /* GC_words_allocd*GC_free_mem_ratio/GC_composite_in_use.        */
  229. void GC_donate_cycles(t)
  230. XR_CT t;
  231. {
  232.     unsigned long r;
  233.     unsigned long r2;
  234.     XR_Ticks ticks;
  235.     int count;
  236.     register int i;
  237.     register int c_in_use = GC_composite_in_use;
  238.     
  239.     if ( c_in_use < MIN_COMPOSITE_IN_USE ) {
  240.         c_in_use  = MIN_COMPOSITE_IN_USE;
  241.     }
  242.     
  243.     GC_parallel_done_signalled = FALSE;
  244.     for (;;) {
  245.         r = 10 * GC_words_allocd * GC_free_mem_ratio
  246.              / c_in_use;
  247.         r2 = r * r / 100;
  248.         if (r2 == 0) r2 = 1;
  249.         ticks = WAKEUP_TICKS;
  250.         count = 1;
  251.         if (r2 > ticks) {
  252.             ticks = 1;
  253.             count = r2/ticks;
  254.         } else {
  255.             ticks /= r2;
  256.             count = 1;
  257.         }
  258.         XR_SetTimeout(&GC_parallel_done_cv, ticks);
  259.         XR_WaitCV(&GC_parallel_done_cv, NIL);
  260.         if (count > 10) {
  261.             XR_LogVMsg
  262.                 "%? Collector fell behind, count = %d, pri = %d, ticks = %d\n",
  263.                 count, t -> ct_thread -> t_pri, ticks);
  264. #        ifdef DEBUG_SCHEDULING
  265.         save_stack(t -> ct_thread -> t_resume.jb_data[2],
  266.                  collector_stack);
  267.         XR_ConsoleMsg("State = %d, pc = 0x%X, stack:\n",
  268.                   t -> ct_thread -> t_sStat,
  269.                   t -> ct_thread -> t_resume.jb_data[0]);
  270.         print_stack(collector_stack);
  271. #        endif
  272.         }
  273.         if (count > 4) count = 4;
  274.         for (i = 0; i < count; i++) {
  275.             if (GC_parallel_done_signalled || XR_ValidateCT(t) < 0) {
  276.                 return;
  277.             }
  278.             if (t -> ct_thread -> t_sStat != XR_SSTAT_READY) break;
  279.             XR_Switch(t -> ct_thread, XR_SSTAT_READY, XR_SWSTAT_THREAD);
  280.         }
  281.     }
  282. }
  283.  
  284. /* High priority process to wake up background gc on a regular basis. */
  285. static XR_Pointer GC_KeepAwake()
  286. {
  287.     struct XR_CTRep last_marker;
  288.  
  289.     last_marker = GC_last_marker;
  290.     XR_SetPriority(gcKeepAwakePriority);
  291.     GC_donate_cycles(&last_marker);
  292.     return(0);
  293. }
  294.  
  295. /* Start up the garbage collection daemon and switch to parallel and    */
  296. /* incremental collection.                        */
  297. /* Idempotent if called only under GC_allocate_ml.            */
  298. bool GC_daemon_started = FALSE;
  299.  
  300. void GC_start_daemon()
  301. {
  302.     struct XR_CTRep daemon_thread;
  303.     
  304.     if (GC_daemon_started) return;
  305.     GC_daemon_started = TRUE;
  306.     XR_InitializeCondition(&GC_parallel_done_cv, XR_WAIT_FOREVER);
  307.     if (XR_TryFork (&daemon_thread, GC_daemon_proc) < 0) {
  308.         GC_printf("Cant fork garbage collection daemon - no threads\n");
  309.     }
  310. }
  311.  
  312. /* Start up a partially parallel marker or collection. */
  313. /* If wait is TRUE, then do not return until the mark  */
  314. /* or collection process mp has finished.  In this     */
  315. /* case, also assume that we are already running at    */
  316. /* the correct priority.                   */
  317. /* No more than one of these should run at once.       */
  318. void
  319. GC_RunParallel( mp, wait )
  320. XR_MesaProc mp;
  321. bool wait;
  322. {
  323.     struct XR_CTRep mark_thread;
  324.     struct XR_CTRep keep_awake_thread;
  325.     
  326. #   ifdef START_PROC_HACK
  327.       XR_MesaProc old_proc = XR_currThread->t_startProc;
  328.       XR_currThread->t_startProc = 0;
  329. #   endif
  330.       
  331.     if (XR_TryFork (&mark_thread, mp) < 0) {
  332.         GC_printf("Cant fork collector - no threads\n");
  333.         (*(mp -> mp_proc))(mp);
  334. #       ifdef START_PROC_HACK
  335.           XR_currThread->t_startProc = old_proc;
  336. #       endif
  337.     return;
  338.     } else {
  339.         if (XR_DetachCT(&mark_thread) < 0) {
  340.            GC_printf("Couldn't detach collector thread\n");
  341.         }
  342.         GC_last_marker = mark_thread;
  343.     }
  344.     
  345. #   ifdef START_PROC_HACK
  346.       XR_currThread->t_startProc = old_proc;
  347. #   endif
  348.     /* Start a high priority process to donate cycles to the low priority */
  349.     /* marker process.                              */
  350.       if (wait) {
  351.         GC_donate_cycles(&mark_thread);
  352.       } else {
  353.         if (XR_TryFork (&keep_awake_thread, KeepAwakeProc) < 0) {
  354.           GC_printf("Cant fork keep awake thread - no threads\n");
  355.         } else {
  356.           if (XR_DetachCT(&keep_awake_thread) < 0) {
  357.              GC_printf("Couldn't detach keep awake thread\n");
  358.           }
  359.         }
  360.       }
  361.       
  362. #   ifdef DEBUG_PAR_GC
  363.       GC_last_gc_no = GC_gc_no;
  364.       XR_GetCurrent(&GC_last_forker);
  365. #   endif DEBUG_PAR_GC
  366. }
  367.  
  368. # ifdef PRINTTIMES
  369.   int GC_started_stats = 0;    /* Started statistics at GC number ... */
  370.   int GC_total_pause_time = 0;    /* Total pause time since start of stats */
  371.   int GC_max_pause_time = 0;    /* Max pause time since start of stats */
  372.                   /* Times are in milliseconds.        */
  373.  
  374.   void GC_reset_stats() {
  375.     GC_started_stats = GC_gc_no;
  376.     GC_total_pause_time = 0;
  377.     GC_max_pause_time = 0;
  378.   }
  379.   
  380.   void GC_print_stats() {
  381.     register int n_colls = GC_gc_no - GC_started_stats;
  382.     
  383.     if (n_colls == 0) {
  384.       XR_PrintF("No collections\n");
  385.     } else {
  386.       XR_PrintF("%d collections: Ave, max pause: %d, %d msecs\n",
  387.                 n_colls, (GC_total_pause_time + (n_colls >> 1))/n_colls,
  388.                 GC_max_pause_time);
  389.     }
  390.   }
  391. # endif
  392.  
  393. /* Run proc with all threads running at less than max priority stopped.    */
  394. /* The caller should be running on vp 0, and will continue to do    */
  395. /* so.                                    */
  396. void
  397. GC_RunExclusive( proc, clientData )
  398.     void (*proc)(/* XR_Pointer data */);
  399.     XR_Pointer clientData;
  400. {
  401.     int ans, err;
  402.     XR_Pri oldPri;
  403.     bool Oexclusive = GC_running_exclusive;
  404.     unsigned long anyProcessor = scop_processorArgAny;
  405.     unsigned long noProcessor = scop_processorArgNone;
  406.     unsigned long processor0 = scop_processorArgVP(0);
  407. #   ifdef PRINTTIMES
  408.     struct timeval start_time;
  409. #    ifdef UNDEFINED
  410.         struct timeval interm_time1;
  411.         struct timeval interm_time2;
  412. #    endif
  413.     struct timeval end_time;
  414.     int stop_time; /* Time during which world was stopped, in msecs */
  415. #    ifdef UNDEFINED
  416.         int time1;
  417.         int time2;
  418. #    endif
  419. #   endif
  420.  
  421. #   define CHECKANS(i) if(ans < 0) { err = i; goto Bad; }
  422.  
  423.     oldPri = XR_GetPriority();
  424.     ans = XR_SchedCtl(
  425.             XR_SchedCtlWhichSelf(),
  426.             scop_setPriority,
  427.             ((unsigned long *)(&gcExclusivePriority))
  428.         );
  429.     CHECKANS(0);
  430.     XR_AcquireVDWriteLock();     /* We will need to update dirty bits. */
  431.                      /* We can't acquire locks with the    */
  432.                      /* world stopped.               */
  433.     XR_AcquireIOPOrderLocks();  /* Acquire in case we have to issue an */
  434.                     /* IOP order, e.g. to protect memory.  */
  435.     ans = XR_SchedCtlLock(TRUE);
  436.     CHECKANS(1);
  437. #   ifdef PRINTTIMES
  438.     if (gettimeofday(&start_time,0) < 0) {
  439.         XR_ConsoleMsg("gettimeofday failed\n");
  440.     }
  441. #   endif
  442.     ans = XR_SchedCtlAll(
  443.             /*othersOp*/    scop_setProcessor,
  444.             /*othersArgp*/    &noProcessor,
  445.             /*myOp*/        scop_nop,
  446.             /*myArgp*/        &processor0
  447.         );
  448.     CHECKANS(2);
  449.     ans = XR_SchedCtlWait();
  450.     CHECKANS(3);
  451.  
  452.     if( proc != NIL ) {
  453. #       ifdef UNDEFINED
  454.         if (gettimeofday(&interm_time1,0) < 0) {
  455.             XR_ConsoleMsg("gettimeofday failed\n");
  456.         }
  457. #    endif
  458.         XR_Yield();    /* make sure stack is in mem, the SP value    */
  459.                         /* known to the scheduler is up-to-date.      */
  460.                         /* This isn't really necessary, since we are  */
  461.                         /* only called from the GC daemon.  That's a  */
  462.                         /* a good thing, since any registers saved by */
  463.                         /* XR_Yield, etc., won't be seen by the       */
  464.                         /* collector.                                 */
  465.  
  466.         Oexclusive = GC_running_exclusive;
  467.     GC_running_exclusive = TRUE;
  468.     if (XR_vpe -> vpe_index != 0) {
  469.         XR_Panic("GC_RunExclusive: Not on vp 0");
  470.     }
  471.         (*proc)(clientData);
  472.         GC_running_exclusive = Oexclusive;
  473.     }
  474. #   ifdef UNDEFINED
  475.     if (gettimeofday(&interm_time2,0) < 0) {
  476.         XR_ConsoleMsg("gettimeofday failed\n");
  477.     }
  478. #   endif
  479.  
  480.     ans = XR_SchedCtlAll(
  481.             scop_setProcessor,
  482.             &anyProcessor,
  483.             scop_nop,
  484.             &processor0
  485.         );
  486.     CHECKANS(4);
  487.     
  488.     ans = XR_SchedCtlUnlock();
  489.     CHECKANS(5);
  490.     
  491.     XR_ReleaseVDWriteLock();
  492.     XR_ReleaseIOPOrderLocks();
  493.     
  494.     XR_SetPriority(oldPri);
  495. #   ifdef PRINTTIMES
  496.     if (gettimeofday(&end_time,0) < 0) {
  497.         XR_ConsoleMsg("gettimeofday failed\n");
  498.     }
  499.     stop_time = 1000*(end_time.tv_sec - start_time.tv_sec);
  500.     stop_time += (end_time.tv_usec - start_time.tv_usec)/1000;
  501.     XR_LogVMsg "Stopped world for %d msecs\n",
  502.                stop_time);
  503.     GC_total_pause_time += stop_time;
  504.     if (stop_time > GC_max_pause_time) GC_max_pause_time = stop_time;
  505. #    ifdef UNDEFINED
  506.         time1 = 1000*(interm_time1.tv_sec - start_time.tv_sec);
  507.         time1 += (interm_time1.tv_usec - start_time.tv_usec)/1000;
  508.         XR_LogVMsg "First intermediate time at %d msecs\n", time1);
  509.         time2 = 1000*(interm_time2.tv_sec - start_time.tv_sec);
  510.         time2 += (interm_time2.tv_usec - start_time.tv_usec)/1000;
  511.         XR_LogVMsg "Second intermediate time at %d msecs\n", time2);
  512. #    endif
  513. #   endif
  514.  
  515.     
  516.     return;
  517.  
  518.   Bad:
  519.     XR_ConsoleMsg("%? schedctl ans %d err %d\n", ans, err);
  520.     XR_Panic("GCRunExclusive");
  521. #   undef CHECKANS
  522. }
  523.  
  524.  
  525.  
  526. /* Return a new block of memory. */
  527. struct hblk *
  528. GC_get_sys_mem(size)
  529.     unsigned long size; /* increment, really! */
  530.     /* Returns (XR_Pointer)0  on failure. */
  531. {
  532.     bool got_requested_size = TRUE;
  533.     struct hblk *thishbp;
  534.     struct XR_SegRep tSeg;
  535.  
  536.     if( ! I_HOLD_ML(&(GC_allocate_ml)) )
  537.         XR_Panic("GC_get_sys_mem 0");
  538.  
  539.     size = XR_RoundToPage(size, XR_ROUND_UP);
  540.     if( (((XR_Pointer)(GC_sys_mem_end)) + size) > XR_sysArea->sa_heapLimit ) {
  541.         return ((struct hblk *)0);
  542.     }
  543.  
  544.     thishbp = (struct hblk *)
  545.         (XR_sysArea->sa_heapSeg.seg_addr+XR_sysArea->sa_heapSeg.seg_bytes);
  546.     XR_InitSeg2( &tSeg, ((XR_Pointer)(thishbp)),  size );
  547.     if( XR_MapSharedHeapSeg(&tSeg) < 0 ) return ((struct hblk *)0);
  548.     XR_ExtendSeg( &(XR_sysArea->sa_heapSeg), size);
  549.     XR_sysArea->sa_heapNum += 1;
  550.     
  551. #   ifdef PRINTSTATS
  552.       GC_vprintf( "Adding to heap with %d shared bytes at addr 0x%X.\n",
  553.               size, thishbp );
  554. #   endif
  555.  
  556.     return (thishbp); /* success */
  557. }
  558.  
  559. /* The analogous routine, but intended to be called during the startup  */
  560. /* process.  May only be called once.                    */
  561. struct hblk *
  562. GC_get_sys_mem_initial(size)
  563.     unsigned long size;
  564. {
  565.     struct hblk * thishbp;
  566.     
  567.     size = XR_RoundToPage(size, XR_ROUND_UP);
  568.     if( ((XR_sysArea->sa_heapSeg.seg_addr) + size) 
  569.         > XR_sysArea->sa_heapLimit ) {
  570.         return ((struct hblk *)0);
  571.     }
  572.  
  573.     thishbp = (struct hblk *) (XR_sysArea->sa_heapSeg.seg_addr);
  574.  
  575.     XR_ExtendSeg( &(XR_sysArea->sa_heapSeg), size);
  576.     XR_MapSharedHeapSeg( &(XR_sysArea->sa_heapSeg) );
  577.     XR_sysArea->sa_heapNum += 1;
  578.  
  579. #   ifdef PRINTSTATS
  580.       GC_vprintf("Startup: Adding to heap with %d shared bytes at addr 0x%X.\n",
  581.              size, thishbp );
  582. #   endif
  583.  
  584.     return (thishbp); /* success */
  585. }
  586.  
  587.  
  588. bool
  589. XR_Increase_Heap(size)
  590.     unsigned size; /* increment */
  591. {
  592.     bool ans;
  593.  
  594.     if( I_HOLD_ML(&GC_allocate_ml) )
  595.         XR_Panic("Increase_Heap 0");
  596.     XR_MonitorEntry( &GC_allocate_ml );
  597.     ans = GC_expand_hp(divHBLKSZ(size + HBLKSIZE - 1), FALSE);
  598.     XR_MonitorExit( &GC_allocate_ml );
  599.     return ans;
  600. }
  601.  
  602.  
  603. /* Lock this thread to vp 0, so that UNIX stack can be relied upon,    */
  604. /* and so that I can relieably do a directed yield to another thread    */
  605. /* that has executed this call.                        */
  606. /* This stays in effect until thread termination.            */
  607. void
  608. GC_lock_to_fixed_vp ()
  609. {
  610.     int ans;
  611.     unsigned long processor0 = scop_processorArgVP(0);
  612.  
  613.     ans = XR_SchedCtl(
  614.         XR_SchedCtlWhichSelf(),
  615.         scop_setProcessor,
  616.         &processor0
  617.     );
  618.     if (ans < 0) GC_abort("GC_lock_to_fixed_vp 0");
  619.     ans = XR_SchedCtlWait();
  620.     if (ans < 0) GC_abort("GC_lock_to_fixed_vp 1");
  621. }
  622.  
  623.